package com.zjw.zy.coreui.view

import android.annotation.SuppressLint
import android.content.Context
import android.text.InputType
import android.util.AttributeSet
import android.view.Gravity
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.inputmethod.BaseInputConnection
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import android.view.inputmethod.InputMethodManager
import android.widget.LinearLayout
import android.widget.TextView
import com.blankj.utilcode.util.Utils
import com.zjw.zy.R
import com.zjw.zy.utils.ResourcesUtils
import java.lang.StringBuilder

/**
 * @author ：zhong.jw
 * @date ：Created in 2022/12/7 15:01
 */
class NumberInputView : LinearLayout {

    companion object {
        private const val TAG = "NumberInputView"

        const val NUMBER_TYPE = "number"
        const val ID_TYPE = "id"
    }

    private var maxCount = 0
    private var type: String = NUMBER_TYPE

    //-1~18
    //-1是未输入状态
    private var currentIndex = -1


    private var mListener: Listener? = null

    private var isInit = false


    constructor(context: Context?) : super(context) {
    }

    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
        doInit(context, attrs)
    }

    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        doInit(context, attrs)
    }

    private val items: List<TextView> by lazy {

        val ly = LayoutParams(0, -1)
        ly.weight = 1f
        ly.marginStart = 5

        val drawable = ResourcesUtils.getDrawable(R.drawable.access_love_id_color)

        val list = ArrayList<TextView>()
        (1..maxCount).forEach { _ ->
            val textView = TextView(context)
            textView.layoutParams = ly
            textView.background = drawable
            textView.gravity = Gravity.CENTER
            list.add(textView)
        }
        list
    }

    private fun doInit(context: Context?, attrs: AttributeSet?) {
        if (!isInit) {
            context?.let {
                it.obtainStyledAttributes(attrs, R.styleable.NumberInputView).apply {
                    type = this.getString(R.styleable.NumberInputView_input_type) ?: NUMBER_TYPE
                    maxCount = if (type == ID_TYPE) {
                        18
                    } else {
                        this.getInt(R.styleable.NumberInputView_number_count, 0)
                    }
                    this.recycle()
                }
            }


            items.forEach { addView(it) }
            isInit = true
        }
    }


    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        return true
    }


    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {
                this.isFocusable = true
                this.isFocusableInTouchMode = true
                this.requestFocus()
            }

            MotionEvent.ACTION_UP -> {
                requestSoftInput()
            }
        }

        return true
    }

    private fun requestSoftInput() {
        val imm =
            Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager

        imm.showSoftInput(this, 0)
    }

    override fun onCheckIsTextEditor(): Boolean {
        return true
    }

    override fun onCreateInputConnection(outAttrs: EditorInfo?): InputConnection {
        outAttrs?.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
        outAttrs?.inputType = InputType.TYPE_NUMBER_FLAG_SIGNED
        return object : BaseInputConnection(this, true) {
            override fun sendKeyEvent(event: KeyEvent?): Boolean {
                if (event?.action == KeyEvent.ACTION_UP) {
                    if (event.keyCode == KeyEvent.KEYCODE_DEL) {
                        deleteNumber()
                        return true
                    }
                    val transValue =
                        transKeyCodeValue(event.keyCode) ?: return true
                    addNumber(transValue)
                }
                return true
            }

            override fun commitText(text: CharSequence?, newCursorPosition: Int): Boolean {
                val c = transCharValue(text) ?: return true

                addNumber(c)

                return true
            }
        }
    }

    private fun addNumber(value: String) {
        val nextIndex = currentIndex + 1
        if (nextIndex < maxCount) {
            items[++currentIndex].text = value
            mListener?.onInputProgress(currentIndex, maxCount)

            if (currentIndex == maxCount - 1) {
                mListener?.onFinish(getValue())
            }
        }
    }

    private fun deleteNumber() {
        if (currentIndex >= 0) {
            items[currentIndex--].text = ""
            mListener?.onInputProgress(currentIndex, maxCount)
        }
    }

    private fun transKeyCodeValue(c: Int): String? {
        val nextIndex = currentIndex + 1
        if (nextIndex > maxCount) {
            return null
        }
        if (c in KeyEvent.KEYCODE_0..KeyEvent.KEYCODE_9) {
            return (c - 7).toString()
        }
        if (c == KeyEvent.KEYCODE_X && nextIndex == 18) {
            return "x"
        }
        return null
    }

    private fun transCharValue(text: CharSequence?): String? {
        if (text?.length != 1) {
            return null
        }
        val nextIndex = currentIndex + 1
        val c = text[0]

        if (c in '0'..'9' || (nextIndex == maxCount && c.equals(
                'x',
                true
            ) && type == ID_TYPE)
        ) {
            return c.toString()
        }

        return null
    }

    fun bindListener(listener: Listener) {
        mListener = listener
    }

    fun getValue(): String {
        val sb = StringBuilder()
        for (item in items) {
            sb.append(item.text)
        }
        return sb.toString()
    }

    fun setValue(value: String) {
        clear()
        value.toCharArray().forEach {
            val code = transCharValue(it.toString()) ?: return
            addNumber(code)
        }
    }

    fun clear() {
        currentIndex = -1;
        items.forEach { it.text = "" }
    }

    interface Listener {
        fun onInputProgress(p: Int, total: Int)

        fun onFinish(value: String)
    }
}